package com.sky.service.impl;

import com.sky.dto.GoodsSalesDTO;
import com.sky.entity.Orders;
import com.sky.exception.BaseException;
import com.sky.mapper.OrderMapper;
import com.sky.mapper.UserMapper;
import com.sky.service.ReportService;
import com.sky.service.WorkspaceService;
import com.sky.vo.*;
import io.swagger.models.auth.In;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
@Slf4j
public class ReportServiceImpl implements ReportService {

    @Autowired
    private OrderMapper orderMapper;

    @Override
    public TurnoverReportVO getTurnoverStatistics(LocalDate begin, LocalDate end) {
        TurnoverReportVO turnoverReportVO = new TurnoverReportVO();
        String dateList = "";
        String turnoverList = "";
        // 1. 把日期区间的每一天存入List
        List<LocalDate> dateArrayList = new ArrayList<>();
        LocalDate currDate = begin;
        while (!currDate.equals(end)){
            dateArrayList.add(currDate);
            // 下一天
            currDate = currDate.plusDays(1);
        }
        // 把最后一天加入列表
        dateArrayList.add(end);
        // StringUtils.join(dateArrayList,",") 工具类把集合转换为字符串，第2个参数就是间隔符
        dateList = StringUtils.join(dateArrayList,",");
        log.info("[日期列表] 修订前：{}",dateList);
        dateList = dateList.replaceAll(LocalDate.now().getYear()+"-","");
        log.info("[日期列表] 修订后:{}",dateList);
        // 2. 遍历日期列表，查询每天的销售额
        List<Double> turnoverArrayList = new ArrayList<>();
        for(LocalDate localDate:dateArrayList){
            // 查询时，需要知道每天的起始时间
            LocalDateTime beginTime = LocalDateTime.of(localDate, LocalTime.MIN);
            LocalDateTime endTime = LocalDateTime.of(localDate, LocalTime.MAX);
            // 调用mapper查询
            Map queryParam = new HashMap();
            queryParam.put("status", Orders.COMPLETED);
            queryParam.put("beginTime", beginTime);
            queryParam.put("endTime", endTime);
            Double sumResult =  orderMapper.selectByMap(queryParam);
            // 如果数据库返回的是null，需要赋值为0
            if(sumResult == null ){
                sumResult = 0d;
            }
            // 存入列表
            turnoverArrayList.add(sumResult);
        }
        turnoverList = StringUtils.join(turnoverArrayList,",");

        log.info("[营业额列表] {}",turnoverList);
        // 3. 把日期和销售额转换为字符串
        turnoverReportVO.setDateList(dateList);
        turnoverReportVO.setTurnoverList(turnoverList);
        return turnoverReportVO;
    }

    @Autowired
    private UserMapper userMapper;

    /**
     * 1.把日期期间的每一天存入列表
     * 2.遍历日期列表，获取每天新增用户数及累计用户总数
     * 3.返回前端需要的字符串
     * @param begin
     * @param end
     * @return
     */
    @Override
    public UserReportVO getUserStatistics(LocalDate begin, LocalDate end) {
        UserReportVO userReportVO = new UserReportVO();
       // 1.把日期期间的每一天存入列表
        List<LocalDate> dateArrayList = new ArrayList<>();
        while (!begin.equals(end)){
            dateArrayList.add(begin);
            begin = begin.plusDays(1);
        }
        // 把最后一天存入列表
        dateArrayList.add(end);
       // 2.遍历日期列表，获取每天新增用户数及累计用户总数
        List<Long> newArrayList = new ArrayList<>();
        List<Long> totalArrayList = new ArrayList<>();
        for (LocalDate currDate:dateArrayList){
            // 构建当前的最大时间和最小时间
            LocalDateTime beginTime = LocalDateTime.of(currDate,LocalTime.MIN);
            LocalDateTime endTime = LocalDateTime.of(currDate,LocalTime.MAX);
            // 获取每天的新增用户数量
            Long newUserCount = getUser(beginTime,endTime);
            // 获取每天的累计用户总数量
            Long totalUserCount = getUser(null,endTime);

            newArrayList.add(newUserCount);
            totalArrayList.add(totalUserCount);
        }
       // 3.返回前端需要的字符串

        userReportVO.setDateList(StringUtils.join(dateArrayList,","));
        userReportVO.setNewUserList(StringUtils.join(newArrayList,","));
        userReportVO.setTotalUserList(StringUtils.join(totalArrayList,","));
        return userReportVO;
    }

    /**
     * 1.把日期区间放入列表
     * 2.遍历日期列表，计算每天的订单总数量及有效数量（数据库）
     * 3.准备前端需要的数据（java代码的逻辑）
     * @param begin
     * @param end
     * @return
     */
    @Override
    public OrderReportVO getOrdersStatistics(LocalDate begin, LocalDate end) {
        OrderReportVO orderReportVO = new OrderReportVO();
        // 1.把日期区间放入列表
        List<LocalDate> dateArrayList = new ArrayList<>();
        while (!begin.equals(end)){
            dateArrayList.add(begin);
            begin = begin.plusDays(1);
        }
        // 把最后一天存入列表   
        dateArrayList.add(end);
        // 2.遍历日期列表，计算每天的订单总数量及有效数量（数据库）
        List<Long> validArrayList = new ArrayList<>();
        List<Long> totalArrayList = new ArrayList<>();
        Long totalCount = 0L;
        Long validCount = 0L;
        for (LocalDate currDate:dateArrayList){
            // 构建当前的最大时间和最小时间
            LocalDateTime beginTime = LocalDateTime.of(currDate,LocalTime.MIN);
            LocalDateTime endTime = LocalDateTime.of(currDate,LocalTime.MAX);
            // 使用公共方法，获取订单数量
            // 先获取有效订单
            Long validOrderCount = getOrderCount(beginTime,endTime,Orders.COMPLETED);
            Long totalOrderCount = getOrderCount(beginTime,endTime,null);
            // 累计有效订单数和总的订单数
            validCount = validCount + validOrderCount;
            totalCount = totalCount+totalOrderCount;

            // 把每天获取的订单总数量和有效数量存入列表
            validArrayList.add(validOrderCount);
            totalArrayList.add(totalOrderCount);
        }
        // 3.准备前端需要的数据（java代码的逻辑）

        orderReportVO.setDateList(StringUtils.join(dateArrayList,","));

        orderReportVO.setValidOrderCount(validCount.intValue());
        orderReportVO.setTotalOrderCount(totalCount.intValue());
        double completionRate = 1.0*validCount/totalCount;
        orderReportVO.setOrderCompletionRate(completionRate);
        orderReportVO.setValidOrderCountList(StringUtils.join(validArrayList,","));
        orderReportVO.setOrderCountList(StringUtils.join(totalArrayList,","));

        return orderReportVO;
    }

    @Override
    public SalesTop10ReportVO getSalesTop10(LocalDate begin, LocalDate end) {
        SalesTop10ReportVO salesTop10ReportVO = new SalesTop10ReportVO();
        // 调用mapper获取数据
        List<GoodsSalesDTO> goodsSalesDTOList =  orderMapper.selectSalesTop10(begin,end);
        // 遍历结果集，存储名字列表与份数列表
        List<String> nameList = new ArrayList<>();
        List<Integer> numberList = new ArrayList<>();
        for (GoodsSalesDTO goods:goodsSalesDTOList){
            nameList.add(goods.getName());
            numberList.add(goods.getNumber());
        }

        salesTop10ReportVO.setNameList(StringUtils.join(nameList,","));
        salesTop10ReportVO.setNumberList(StringUtils.join(numberList,","));
        return salesTop10ReportVO;
    }
    @Autowired
    private WorkspaceService workspaceService;
    @Override
    public void exportExcel(HttpServletResponse response) {
        // 读取模板文件
        InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("excel/运营数据报表模板.xlsx");
        try{
            // 构建Excel
            XSSFWorkbook excel = new XSSFWorkbook(inputStream);
            // 操作excel
            // 构建日期区间
            LocalDate begin = LocalDate.now().minusDays(30);
            LocalDate end = LocalDate.now().minusDays(1);
            // 获取30天的总运营数据
            LocalDateTime beginTime = LocalDateTime.of(begin,LocalTime.MIN);
            LocalDateTime endTime = LocalDateTime.of(end,LocalTime.MAX);
            BusinessDataVO businessData = workspaceService.getBusinessData(beginTime, endTime);
            // 把数据写入excel中
            XSSFSheet sheet = excel.getSheetAt(0);
            // 定位单元格
            sheet.getRow(1).getCell(1).setCellValue(begin+"至"+end);
            // 定位到第4行
            XSSFRow row = sheet.getRow(3);
            // 营业额
            row.getCell(2).setCellValue(businessData.getTurnover());
            row.getCell(4).setCellValue(businessData.getOrderCompletionRate());
            row.getCell(6).setCellValue(businessData.getNewUsers());
            row = sheet.getRow(4);
            row.getCell(2).setCellValue(businessData.getValidOrderCount());
            row.getCell(4).setCellValue(businessData.getUnitPrice());
            // 获取30天的详细数据（具体每天的数据）
            for (int i = 0; i < 30 ; i++) {
                // 获取当天的开始与结束
                LocalDate currDate = begin.plusDays(i);
                // 构建一天的开始时间与结束时间
                beginTime = LocalDateTime.of(currDate,LocalTime.MIN);
                endTime = LocalDateTime.of(currDate,LocalTime.MAX);
                businessData = workspaceService.getBusinessData(beginTime, endTime);
                // 定位行
                row = sheet.getRow(7+i);
                row.getCell(1).setCellValue(currDate+"");
                row.getCell(2).setCellValue(businessData.getTurnover());
                row.getCell(3).setCellValue(businessData.getValidOrderCount());
                row.getCell(4).setCellValue(businessData.getOrderCompletionRate());
                row.getCell(5).setCellValue(businessData.getUnitPrice());
                row.getCell(6).setCellValue(businessData.getNewUsers());
            }

            // 把excel发送给客户端
            ServletOutputStream outputStream = response.getOutputStream();
            // 客户端开始收
            excel.write(outputStream);

            // 关闭资源（自己创建的）
            inputStream.close();
            excel.close();
        }catch (Exception e){
            e.printStackTrace();
            throw  new BaseException("导出报表出错了,"+e.getMessage());
        }

    }

    private Long getOrderCount(LocalDateTime beginTime, LocalDateTime endTime, Integer completed) {
        // 根据日期区间，查询数据库，获取订单数据量
        Map queryParam = new HashMap();
        queryParam.put("beginTime", beginTime);
        queryParam.put("endTime", endTime);
        queryParam.put("status", completed);
        Long count = orderMapper.selectByCount(queryParam);
        return count!=null ? count : 0L;
    }

    /**
     * 公共方法
     * 根据参数，查询用户统计
     * @param beginTime 开始时间
     * @param endTime 结束时间
     * @return
     */
    private Long getUser(LocalDateTime beginTime,LocalDateTime endTime){
        Map queryParam = new HashMap();
        queryParam.put("beginTime", beginTime);
        queryParam.put("endTime", endTime);
        Long userCount = userMapper.selectCountByMap(queryParam);
        if (userCount == null){
            userCount = 0L;
        }
        return userCount;
    }
}
